package ar.com.e2solver;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import ar.com.e2solver.conf.E2SolverConfiguration;
import ar.com.e2solver.conf.PuzzleTheme;
import ar.com.e2solver.exception.BusinessException;
import ar.com.e2solver.model.Piece;
import ar.com.e2solver.model.Puzzle;
import ar.com.e2solver.solver.GAResult;
import ar.com.e2solver.solver.GeneticAlgorithmSolver;
import ar.com.e2solver.solver.Individual;
import ar.com.e2solver.solver.PuzzlePrinter;
import ar.com.e2solver.solver.SolverResult;

public class E2Solver {

	private PuzzleTheme puzzleTheme;
	private E2SolverConfiguration solverConfiguration;

	public E2Solver(PuzzleTheme puzzleTheme) throws BusinessException {
		this.puzzleTheme = puzzleTheme;
		this.solverConfiguration = new E2SolverConfiguration();
	}

	public SolverResult run() throws BusinessException {
		int populationSize = solverConfiguration.getPopulationNumber();
		int iterationsNumber = solverConfiguration.getIterations();
		boolean showLog = solverConfiguration.getShowLog();

		GeneticAlgorithmSolver ga = new GeneticAlgorithmSolver(
				getPuzzleTheme(), populationSize, iterationsNumber, showLog);
		GAResult result = ga.solve();

		validateIntegrity(result);
		
		// si esta resuelto imprime el rompecabezas!!
		if(result.getBestIndividual().getFitnessValue() == result.getMaxPossibleFitness()){
			System.out.println(result.getBestIndividual().getPuzzle());
			PuzzlePrinter.print(result.getBestIndividual().getPuzzle());
		}

		return result;
	}

	/**
	 * Verifica la legalidad del rompecabezas, es decir, que todas las piezas sean distintas
	 * 
	 * @param result
	 * @throws BusinessException
	 */
	private void validateIntegrity(GAResult result) throws BusinessException {
		Puzzle bestPuzzle = result.getBestIndividual().getPuzzle();
		int numberMaxPieces = bestPuzzle.getColumnNumbers()
				* bestPuzzle.getRowsNumber();

		for (Iterator<Individual> iterator = result.getFinalPopulation().getIndividuals().iterator(); iterator.hasNext();) {
			Individual individual = iterator.next();

			Set<Piece> pieces = new HashSet<Piece>();
			pieces.addAll(individual.getPuzzle().getPieces());
			if (numberMaxPieces != pieces.size()) {
				throw new BusinessException(
						"Se rompio la integridad de las piezas");
			}
		}

	}

	public E2SolverConfiguration getSolverConfiguration() {
		return solverConfiguration;
	}

	public void setSolverConfiguration(E2SolverConfiguration solverConfiguration) {
		this.solverConfiguration = solverConfiguration;
	}

	public PuzzleTheme getPuzzleTheme() {
		return puzzleTheme;
	}

	public void setPuzzleTheme(PuzzleTheme puzzleTheme) {
		this.puzzleTheme = puzzleTheme;
	}
}
